package com.sentongo.tracker;

import java.lang.reflect.Array;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Random;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity  implements OnClickListener, SensorEventListener{
	
	private boolean instatiated = false; // Set to true once all variables are ready for a test run.
	private Sensor accel, gyro; // Accelerometer sensor
	private boolean started = false;
	private TextView x_output, y_output, z_output, large_Secs, degrees, distance;
	private Button btnStart, btnStop, btnSave, btnCalibrate;	
	private SensorManager mSensorManager;
	private long startTime, timeInMilliseconds;
	private ArrayList<AccData> sensorData;
	private ArrayList<Integer> proccessedSeconds;
	private float totalDistance;
	private Random random = new Random();
	private int lastSecond=0, secondsElapsed=0, initialVelocity=-5;
	 
	

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);      
        if(!instatiated){
        	instatiate();
        }
        
    }


	private void instatiate() {
		
		//Toast.makeText(getApplicationContext(), "Instatiated!! :)", Toast.LENGTH_LONG).show(); 
		mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		accel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		gyro = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		mSensorManager.registerListener(this, accel , SensorManager.SENSOR_DELAY_FASTEST);
		mSensorManager.registerListener(this, gyro , SensorManager.SENSOR_DELAY_GAME);
		
		if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
			  Toast.makeText(getApplicationContext(), "Accelerometer Present", Toast.LENGTH_LONG).show();
			  }
			else {
				Toast.makeText(getApplicationContext(), "Accelerometer NOT Present", Toast.LENGTH_LONG).show();
			  }
		if (mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION) != null){
			Toast.makeText(getApplicationContext(), "Orientation sensor Present", Toast.LENGTH_LONG).show();
			  }
			else {
				Toast.makeText(getApplicationContext(), "Gyro NOT Present", Toast.LENGTH_LONG).show();
			  }
		
		
		// Assign Textviews
		x_output = (TextView) findViewById(R.id.x_data);
		y_output = (TextView) findViewById(R.id.y_data);
		z_output = (TextView) findViewById(R.id.z_data);
		large_Secs = (TextView) findViewById(R.id.Distance_Text);
		degrees = (TextView) findViewById(R.id.feedbackAngle);
		distance = (TextView) findViewById(R.id.feedbackDistance);
		
		// Assign Buttons
		btnStart = (Button) findViewById(R.id.Start_btn);
		btnStop = (Button) findViewById(R.id.Stop_btn);
		btnSave = (Button) findViewById(R.id.Save_btn);
		btnCalibrate = (Button) findViewById(R.id.Calibrate_btn);

		
		// Button listeners
		btnStart.setOnClickListener(this);
		btnStop.setOnClickListener(this);
		btnSave.setOnClickListener(this);
		btnCalibrate.setOnClickListener(this);
		
		// Set buttons clickable
		enableButton(btnCalibrate,btnSave,btnStart);
		disableButton(btnStop);
		
		// Assin arrays
		sensorData = new ArrayList<AccData>();
		proccessedSeconds = new ArrayList<Integer>();
		
		// Set Angle textview text
		displayToTextView(degrees, "0"+(char) 0x00B0);
		
		// Variables
		startTime = 0;
		totalDistance = 0;
		
		// Update variable
		instatiated = true;
	}

   
	@Override
    protected void onResume(){
    	super.onResume();
    	//mSensorManager.registerListener(this, accel, SensorManager.SENSOR_DELAY_NORMAL);
    	if(!instatiated){
    		instatiate();
    	}
    }
    
    @Override
    protected void onPause() {
    	super.onPause();
    	resetTextDisplays();
    	instatiated = false;
    	started=false;
    	mSensorManager.unregisterListener(this,accel);
    	mSensorManager.unregisterListener(this,gyro);
		
	}
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        
        // Inflate the menu; this adds items to the action bar if it is present.
    	if(!started){
    		getMenuInflater().inflate(R.menu.main, menu);
    	}
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        
        	
    	int id = item.getItemId();
        /*if (id == R.id.action_settings) {
            return true;
        }*/
        switch (id) {
			case R.id.action_settings:
				return true;
				//break;
			case R.id.menu1_op1:
				if(item.isChecked()) item.setChecked(false);
				else item.setChecked(true);
				return true;
			case R.id.menu1_op2:
				if(item.isChecked()) item.setChecked(false);
				else item.setChecked(true);
				return true;
			default:
				return super.onOptionsItemSelected(item);
		}
       
    }


   
    
	@Override
	public void onClick(View v) {
		
		// Switch statement to detect pressed button
		switch(v.getId()){
			
			case R.id.Start_btn:
				totalDistance = 0;
				started = true;
				startTime = SystemClock.uptimeMillis(); 			// Set current time (milliseconds) as start time
				disableButton(btnStart,btnCalibrate,btnSave);
				enableButton(btnStop);
				break;
			
			case R.id.Stop_btn:
				started = false;
				startTime = 0;
				
				disableButton(btnStop);
				sensorData = new ArrayList<AccData>();
				proccessedSeconds = new ArrayList<Integer>();
				//averagedSensorData = new ArrayList<AccData>();
				enableButton(btnStart,btnCalibrate,btnSave);
				//resetTextDisplays();
				break;
				
			case R.id.Calibrate_btn:
				Toast.makeText(getApplicationContext(), "Calibrate",Toast.LENGTH_LONG).show();
				
				break;
				
			case R.id.Save_btn:
				Toast.makeText(getApplicationContext(), "Save",Toast.LENGTH_LONG).show();
				break;
				
			default:
				break;
		}
		
	}


	/**
	 * Disables one or more parsed buttons
	 * @param buttons
	 */
	private void disableButton(Button...buttons ) {
		for(Button b: buttons){
			b.setEnabled(false);
		}
		
	}
	
	/**
	 * Enables one or more buttons
	 * @param buttons
	 */
	private void enableButton(Button...buttons ) {
		for(Button b: buttons){
			b.setEnabled(true);
		}
		
	}


	/**
	 * Resets the values in the text views for x,y,x,timer views
	 */
	private void resetTextDisplays() {
		displayToTextView(x_output, "0");
		displayToTextView(y_output, "0");
		displayToTextView(z_output, "0");
		displayToTextView(large_Secs, "Let's begin");
		displayToTextView(degrees, "0"+(char) 0x00B0);
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		
		// TODO Auto-generated method stub
		displayToTextView(degrees, Float.toString(totalDistance));
		//synchronized (this) {
			switch (event.sensor.getType()) {
			case Sensor.TYPE_ACCELEROMETER:
				if(started && instatiated){
					
					// Raw unprocessed Data from, sensors
					float rawX = event.values[0];
					float rawY = event.values[1];
					float rawZ = event.values[2];	
					//int intervalMilliseconds
					
					// Compute Time
					timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
					secondsElapsed = (int)(timeInMilliseconds / 1000);
					int minutes = secondsElapsed / 60;
		            secondsElapsed = secondsElapsed % 60;
		            
		           
		           	
		            // Display Data on Screen
		            displayToTextView(large_Secs, String.format("%02d", secondsElapsed));
					/*displayToTextView(x_output, Float.toString(rawX));
					displayToTextView(y_output, Float.toString(rawY));
					displayToTextView(z_output, Float.toString(rawZ));*/
					
					// Store data from the sensors into Arraylist
					
					//AccData data = new AccData(secondsElapsed, rawX, rawY, rawZ);
					sensorData.add(new AccData(secondsElapsed, rawX, rawY, rawZ));
					//distance.setText(sensorData.size());
					//
					if(/*(secondsElapsed>0)* && */(secondsElapsed % 1 == 0)&&(secondsElapsed!=0)){
					if(lastSecond < secondsElapsed){	  
						if(proccessedSeconds.size()>0){
							if(proccessedSeconds.get(proccessedSeconds.size()-1) != secondsElapsed){
								ArrayList<AccData> temp = new ArrayList<AccData>();
								temp = (ArrayList<AccData>) sensorData.clone();
								computeDistance compute = new computeDistance();
								Log.w("size before", Float.toString(sensorData.size()));
								compute.execute(temp);
								//.execute(runnable);
								// Clear the sensorData arraylist
								
								distance.setText("Array for "+ secondsElapsed +"': "+sensorData.size());
								
								
								// Add this second to the proccessedSeconds Arraylist so we don't compute for this second again
								if(proccessedSeconds.get(proccessedSeconds.size()-1) != secondsElapsed){
									proccessedSeconds.add(secondsElapsed);	
								}
								//proccessedSeconds.add(secondsElapsed);
								
								
								//Toast.makeText(getApplicationContext(), "3rd Second!", T).show();
								
								Log.w("a", secondsElapsed+" sec has passed!");
								sensorData.clear();
							}
						}
						else {
							if(!proccessedSeconds.isEmpty()){
								if(proccessedSeconds.get(proccessedSeconds.size()-1) != secondsElapsed){
									proccessedSeconds.add(secondsElapsed);	
								}
							}
							else {
								proccessedSeconds.add(secondsElapsed);
							}
							
						}
						
					}
					}}
				
				break;
			case Sensor.TYPE_ORIENTATION:
				if(started && instatiated){
					//displayToTextView(degrees, Float.toString(event.values[0])+(char) 0x00B0);
					
				}

			default:
				break;
			}
			
			lastSecond = secondsElapsed;
			
		}
	
	//}

	/**
	 * Displays parsed string to the textView
	 * @param textview
	 * @param string
	 */
	private void displayToTextView(TextView textview,String string) {
		textview.setText(string);
	}
	
	
	/**
	 * 
	 * @author JL
	 *
	 */
	public class computeDistance extends AsyncTask<ArrayList<AccData>, ArrayList<AccData>, Float>{

		//@SuppressWarnings("unchecked")
		@Override
		protected Float doInBackground(ArrayList<AccData>... arg0){
			
			//synchronized (arg0[0]) {
				
			
			
			// Moving average to be 
			int averagelMilliseconds = 100, count =0;
			float thisDIstance = 0;
			
			ArrayList<AccData> averagedSensorData = new ArrayList<AccData>();
			// Variables
			float avgX=0, avgY=0, avgZ=0, totalX=0, totalY=0, totalZ=0;
			long timeStamp=0;
			ArrayList<AccData> newList = arg0[0];
			Log.w("size recieved",Float.toString(arg0[0].size()) );
			try{				
				// Perform averaging
			if(arg0[0].size()>=0){
				for(ArrayList<AccData> list : arg0){
				for(int x=0; x < list.size(); x++){
					AccData current = list.get(x);
						thisDIstance = current.getTimestamp();
						timeStamp = current.getTimestamp();
						totalX = totalX +current.getX();
						totalY = totalY +current.getY();
						totalZ = totalZ +current.getZ();
						count = count + 1;
				}
			}
			}
				else{
					averagedSensorData.add(new AccData(timeStamp, avgX, avgY, avgZ));
					return thisDIstance;
				}
			}catch (Exception e) {
				e.printStackTrace();
				// TODO: handle exception
			}
			int randomNumber = random.nextInt(random.nextInt(40000000));
			Log.w("c","random number : "+randomNumber);
			
			for(int i=0; i < randomNumber; i++){
				
				thisDIstance = thisDIstance;
			}
			if(count!=0){
				avgX = totalX/count;
				avgY = totalY/count;
				avgZ = totalZ/count;	
			}
			
			
			averagedSensorData.add(new AccData(timeStamp, avgX, avgY, avgZ));
			
			
			
			
			try {
				if(averagedSensorData.size()>0){
					publishProgress(averagedSensorData);
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				}
			
			
						
			// TODO Auto-generated method stub
			return thisDIstance;
		//	}
			
		}

		
		@Override
		protected void onProgressUpdate(ArrayList<AccData>... progress) {
			
			//AccData pr
			try {
				for(ArrayList<AccData> list2 : progress){
					for(int x=0; x < list2.size(); x++){	
					AccData data2 = list2.get(x);
				    displayToTextView(large_Secs, "* " +Float.toString(data2.getTimestamp()));
					displayToTextView(x_output, Float.toString(data2.getX()));
					displayToTextView(y_output, Float.toString(data2.getY()));
					displayToTextView(z_output, Float.toString(data2.getZ()));
					displayToTextView(distance, "* "+ Float.toString(data2.getTimestamp()));
				}
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			
			
	        //setProgressPercent(progress[0]);
	    }
		
		@Override
		protected void onPostExecute(Float result) {
			//displayToTextView(x_output, "hi");
	        //showDialog("Downloaded " + result + " bytes");
			Log.w("d", "finished "+Float.toString(result));
			//initialVelocity = initialVelocity +
			totalDistance =  result;
			
	    }

		
		
	}
	
	
	
}

